﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Lagash.CodeCamp.Twitter.Lib;
using System.Threading;
using Facebook.Winforms.Components;
using System.Diagnostics;
using System.Net;
using Facebook.Schema;
using System.Configuration;

namespace zPod.TweetMyFace
{
	public partial class Main : Form
	{
		private const string LogToEventViewerKey = "logToEventViewer";
		private const string UserKey = "User";
		private const string FacebookSession = "FacebookSession";
		private const int TwitterCoolingTime = 20;
		private const int RefreshSeconds = 60;
		private const string FacebookAppKey = "109aaef6ff918249a7ef7c7562a7f39c";

		private string _twitterUser;
		private string _twitterPassword;
		private System.Threading.Timer _checkTimer;

		private Twitter _twitterClient;
		private FacebookService _facebookService;

		private DateTime _lastNotificationUpdate = DateTime.Now.ToUniversalTime();
		
		private Queue<notification> _notificationsToSend = new Queue<notification>();
		private object _sync = new object();

		private Queue<string> _logQueue = new Queue<string>();

		public Main()
		{
			_twitterClient = new Twitter();
			_facebookService = new FacebookService();
			_facebookService.ApplicationKey = FacebookAppKey;

			InitializeComponent();

			try
			{
				var preferences = UserPreferencesHelper.LoadPreferences();

				if (preferences.ContainsKey(UserKey))
				{
					txtTwitterUser.Text = preferences[UserKey];
				}

				if (preferences.ContainsKey(FacebookSession))
				{
					//_facebookService.SessionKey = preferences[FacebookSession];
				}

				if (preferences.ContainsKey("UserID"))
				{
					//_facebookService.uid = long.Parse(preferences["UserID"]);
				}
			}
			catch (Exception ex)
			{
				LogException(ex);
			}
		}

		private void btnConnect_Click(object sender, EventArgs e)
		{
			#region Desactivo los controles

			CambiarEstadoControles(false);

			#endregion

			_twitterPassword = txtTwitterPassword.Text;
			_twitterUser = txtTwitterUser.Text;

			bool connectedToTwitter;
			try
			{
				_twitterClient.GetFriends(_twitterUser, _twitterPassword);
				connectedToTwitter = true;
			}
			catch
			{
				connectedToTwitter = false;
			}

			if (connectedToTwitter)
			{
				//_facebookService.ConnectToFacebook(new List<Enums.ExtendedPermissions>() { Enums.ExtendedPermissions.offline_access });
				_facebookService.ConnectToFacebook();
			}

			if (!String.IsNullOrEmpty(_facebookService.SessionKey) && connectedToTwitter)
			{
				try
				{
					UserPreferencesHelper.SavePreferences(new Dictionary<string, string>()
					{
						{UserKey, _twitterUser},
						{FacebookSession, _facebookService.SessionKey},
						{"UserID", _facebookService.uid.ToString()}
					});
				}
				catch (Exception ex)
				{
					LogException(ex);
				}


				_checkTimer = new System.Threading.Timer(
					RefreshMessages,
					null,
					0,
					RefreshSeconds * 1000);
			}
			else
			{
				MessageBox.Show(
					"Verify your Twitter and Facebook credentials",
					"Error connecting",
					MessageBoxButtons.OK,
					MessageBoxIcon.Error);

				CambiarEstadoControles(true);
			}
		}

		private void CambiarEstadoControles(bool estado)
		{
			grpTwitterLogin.Enabled = estado;
			btnConnect.Enabled = estado;
		}

		private void RefreshMessages(object state)
		{
			try
			{
				GetFacebookNotifications();
				ThreadPool.QueueUserWorkItem(o => SendNotificationsToTwitter(), new Object());
			}
			catch (Exception ex)
			{
				LogException(ex);
			}
		}

		private void SendNotificationsToTwitter()
		{
			while (_notificationsToSend.Count > 0)
			{
				try
				{
					lock (_sync)
					{
						// Obtengo la notificacion. Si esta todo bien la desencolo
						var notif = _notificationsToSend.Peek();

						string url = null;
						try
						{
							url = GenerateURL(notif.href);
						}
						catch (Exception ex)
						{
							LogException(ex);
						}

						var tweet = notif.title_text + " " + notif.body_text;

						if (!String.IsNullOrEmpty(url))
						{
							tweet = url + ": " + tweet;
						}

						if (tweet.Length > 140)
						{
							tweet = tweet.Substring(0, 137) + "...";
						}

						_twitterClient.Update(_twitterUser, _twitterPassword, tweet);
						Log(tweet);
						_notificationsToSend.Dequeue();
					}
				}
				catch (Exception ex)
				{
					LogException(ex);
				}

				// le doy tiempo a twitter para que no me banee
				Thread.Sleep(TwitterCoolingTime * 1000);
			}
		}

		private void LogException(Exception ex)
		{
			Log(ex.Message + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error);
		}

		private void Log(string message)
		{
			Log(message, EventLogEntryType.Information);
		}

		private void Log(string message, EventLogEntryType type)
		{
			_logQueue.Enqueue(String.Format("{0} - {1}", type, message));

			bool logToEventViewer;
			if (!Boolean.TryParse(ConfigurationManager.AppSettings[LogToEventViewerKey], out logToEventViewer))
			{
				logToEventViewer = false;
			}

			if (logToEventViewer)
			{
				try
				{
					EventLog.WriteEntry("TweetMyFace", message, type);
				}
				catch
				{
					Debug.WriteLine(message);
				}
			}
		}

		private void GetFacebookNotifications()
		{

			var notifications =
				_facebookService
				.Notifications
				.GetList(_lastNotificationUpdate, false)
				.notifications.notification
				.Where(n => n.is_hidden == 0 && n.is_unread == 1)
				.OrderBy(n => n.created_time);

			_lastNotificationUpdate = DateTime.Now.ToUniversalTime();

			foreach (var notif in notifications)
			{
				_notificationsToSend.Enqueue(notif);
			}
		}

		private DateTime UnixTimeToDateTime(long time)
		{
			return new DateTime(1970, 1, 1).AddSeconds(time);
		}

		private long DateTimeToUnixTime(DateTime time)
		{
			DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
			TimeSpan diff = time - origin;
			return Convert.ToInt64(Math.Floor(diff.TotalSeconds));
		}

		private string GenerateURL(string url)
		{
			string template = "http://tinyurl.com/api-create.php?url={0}";

			using (WebClient client = new WebClient())
			{
				return client.DownloadString(String.Format(template, url));
			}
		}

		private void logTimer_Tick(object sender, EventArgs e)
		{
			while(_logQueue.Count > 0)
			{
				logBox.Items.Add(_logQueue.Dequeue());
			}
		}
	}
}
